package net.lastcoder.ifserver.web;

import net.lastcoder.ifserver.Constants;
import net.lastcoder.ifserver.Globals;
import net.lastcoder.ifserver.packet.PacketParser;
import net.lastcoder.ifserver.packet.Event;
import net.lastcoder.ifserver.packet.Message;
import net.lastcoder.ifserver.packet.Packet;
import net.lastcoder.ifserver.packet.SessionClosePacket;
import net.lastcoder.ifserver.packet.SessionOpenPacket;
import net.lastcoder.ifserver.session.UlaID;

import org.apache.mina.core.buffer.IoBuffer;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;

import static net.lastcoder.ifserver.packet.Packet.TYPE_SET;


/**这是json转if packet的解析
 * auth: WenYF
 * date: 2017/3/13
 */
public class FastJsonParser extends PacketParser {
    private static final Logger Log = LoggerFactory.getLogger(FastJsonParser.class);

    private static final String MAX_PROPERTY_NAME = "web.socket.buffer.size";
    private static final byte startTag = '{';
    private static final byte endTag= '}';

    private int maxBufferSize;

    /**
     * 将数据放在这里面
     */
    private StringBuilder buffer;

    private int tagCounter = 0;
    private boolean findHead;

    private ArrayList<Packet> packets;

    public FastJsonParser() {
        // 32kb
        maxBufferSize = Globals.getXMLProperty(MAX_PROPERTY_NAME, 1024 * 32);
        buffer = new StringBuilder(maxBufferSize);
        packets = new ArrayList<>();

    }

    public void read(String message) {
        Thread thread = Thread.currentThread();
        if (ENABLE_PARSER_DEBUG) {
            Log.debug("thread name = " + thread.getName());
            Log.debug("message : " + message);
        }

        for(int i = 0; i < message.length(); i++) {
            char b = message.charAt(i);
            this.buffer.append(b);

            switch (b) {
                case startTag:
                    tagCounter++;

                    if (tagCounter == 1) {
                        findHead = true;
                    }
                    break;
                case endTag:
                    tagCounter--;

                    if (tagCounter == 0 && findHead) {
                        processData();
                    }
                    break;
                default:
                    if (!findHead) {
                        // 异常
                        return;
                    }
                    break;
            }
        }
    }

    @Override
    public void read(IoBuffer buffer) {
        buffer.mark();
        String dump = buffer.getHexDump();
        Thread thread = Thread.currentThread();
        if (ENABLE_PARSER_DEBUG) {
            Log.debug("thread name = " + thread.getName());
            Log.debug("buffer : " + dump);
        }
        buffer.reset();

        while(buffer.remaining() > 0) {
            char b = (char) buffer.get();
            this.buffer.append(b);

            switch (b) {
                case startTag:
                    tagCounter++;

                    if (tagCounter == 1) {
                        findHead = true;
                    }
                    break;
                case endTag:
                    tagCounter--;

                    if (tagCounter == 0 && findHead) {
                        processData();
                    }
                    break;
                default:
                    if (!findHead) {
                        // 异常
                        buffer.position(buffer.limit());
                        return;
                    }
                    break;
            }
        }
    }

    private void processData() {
        String str = buffer.toString();
        try {
            Packet packet;
            JSONObject json = new JSONObject(str);
            int id = json.getInt("id");
            int type = json.getInt("type");
            String from = null;
            String to = null;
            if (json.has("to")) {
                to = json.getString("to");
            }
            if (json.has("from")) {
                from = json.getString("from");
            }

            json = json.getJSONObject("data");
            switch (type) {
                case Constants.PACKET_TYPE_SESSION_OPEN: {
                    int queryType = json.getInt("type");
                    int protocolVersion = 0;
                    String extra = "";
                    if (queryType == TYPE_SET) {
                        protocolVersion = json.getInt("protocolVersion");
                    }

                    if (json.has("extra")) {
                        extra = json.getString("extra");
                    }

                    SessionOpenPacket openPacket = new SessionOpenPacket((byte) queryType);
                    openPacket.setProtocolVersion((byte) protocolVersion);
                    openPacket.setExtra(extra.getBytes());

                    packet = openPacket;
                    break;
                }
                case Constants.PACKET_TYPE_SESSION_CLOSE: {
                    int queryType = json.getInt("type");
                    String extra = "";

                    if (json.has("extra")) {
                        extra = json.getString("extra");
                    }

                    SessionClosePacket closePacket = new SessionClosePacket((byte) queryType);
                    closePacket.setExtra(extra.getBytes());

                    packet = closePacket;
                    break;
                }
                case Constants.PACKET_TYPE_MESSAGE: {
                    String title = json.getString("title");
                    Object body = "";
                    if (json.has("body")) {
                        body = json.get("body");
                    }

                    Message message = new Message(title);
                    message.setBody(body.toString());

                    packet = message;
                    break;
                }
                case Constants.PACKET_TYPE_EVENT: {
                    int queryType = json.getInt("type");
                    int eventType = json.getInt("eventType");
                    int actionCode = json.getInt("actionCode");
                    Object body = "";
                    if (json.has("body")) {
                        body = json.get("body");
                    }

                    Event event = new Event((short)eventType, (byte)queryType, actionCode);
                    event.setBody(body.toString());

                    packet = event;
                    break;
                }
                default:
                    buffer.delete(0, buffer.length());
                    findHead = false;
                    return;

            }

            packet.setId(id);
            packet.setFromAddress(UlaID.fromAddress(from));
            packet.setToAddress(UlaID.fromAddress(to));

            packets.add(packet);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        buffer.delete(0, buffer.length());
        findHead = false;
    }

    @Override
    public boolean hasPacket() {
        return packets.size() > 0;
    }

    @Override
    public Packet getPacket() {
        return packets.remove(0);
    }
}
